<?php
/**
 * 基于php的gd库进行集成
 * 最低版本支持php5.3
 * 支持图片的缩放
 * 支持图片高斯模糊
 * 处理图片成圆形
 * 图片水印和文字水印
 * 支持jpg，jpeg，png,不支持gif如果需要使用gif可选择imagemagic库相关的lib进行处理
 */

class gdclient
{
    // 底图hanlde 图像的处理都是基于底图的句柄
    protected $imageResource;

    // 句柄数组，用于释放资源
    protected $resourceList = array();

    protected $allow_ext = array('jpg', 'jpeg', 'png');

    public function __construct()
    {
    }

    //function `function`

    // alpha 取值范围为0-127 0表示完全不透明，127表示完全透明
    public function createEmptyImage($width, $height, $backgroundColor, $alpha = 0)
    {
        if ($alpha < 0 || $alpha > 127) {
            throw new Exception("alpha range error!", 1);
        }

        $this->imageResource = imagecreatetruecolor($width, $height);
        $bg = $this->colorallocate($backgroundColor, $alpha);
        imagefill($this->imageResource, 0, 0, $bg);
    }

        // 根据图像创建
    public function imageCreate($src)
    {
        if (empty($src)) {
            throw new Exception("image src is empty");
        }

        if (!is_file($src)) {
            throw  new Exception('file is not exist');
        }


        $this->imageResource = $this->getHandler($src);
    }


    // 因为字体的基线是再左下角，所有设置下x,y的值的时候需要
    public function imageText($size, $angle, $x, $y, $font, $text, $color, $alpha = 0)
    {
        $c = $this->colorallocate($color, $alpha);
        $box = imageftbbox($size, $angle, $font, $text);
        // 通过imageftbbox 获取文本的高度，然后y坐标减去高度即可获取到文字的y点坐标
        imagettftext($this->imageResource, $size, $angle, $x, $y - $box[7], $c, $font, $text);
    }

    // 文字在x轴上剧中显示
    public function imageTextXCenter($size, $angle, $y, $font, $text, $color, $alpha = 0)
    {
        $c = $this->colorallocate($color, $alpha);
        $box = imageftbbox($size, $angle, $font, $text);
        $width = imagesx($this->imageResource);
        // 通过imageftbbox 获取文本的高度，然后y坐标减去高度即可获取到文字的y点坐标
        imagettftext($this->imageResource, $size, $angle, ceil(($width - $box[2]) / 2), $y - $box[7], $c, $font, $text);
    }

    // 文字在y轴上剧中显示
    public function imageTextYCenter($size, $angle, $x, $font, $text, $color, $alpha = 0)
    {
        $c = $this->colorallocate($color, $alpha);
        $box = imageftbbox($size, $angle, $font, $text);
        $height = imagesy($this->imageResource);
        // 通过imageftbbox 获取文本的高度，然后y坐标减去高度即可获取到文字的y点坐标
        $y = ceil($height) / 2 - ($box[7] - $box[1]) / 2;
        imagettftext($this->imageResource, $size, $angle, $x, $y, $c, $font, $text);
    }

    // 图片合并
    //$roatteColor 图片旋转填充颜色
    // imagecopy 不支持透明的图片合成，合成的图片会变成白色
    public function imagecopy($src, $dx, $dy, $sx, $sy, $sw, $sh, $blur = false, $rotate = 0, $roatteColor = "")
    {
        $src = $this->getHandler($src);
        if ($rotate != 0) {
            $src = imagerotate($src, $rotate, $roatteColor);
        }

        if ($blur) {
            $src = $this->blur($src);
        }

        imagecopy($this->imageResource, $src, $dx, $dy, $sx, $sy, $sw * imagesx($src), $sh * imagesy($src));
    }

    // 图片合成支持，png等透明图像的合成
    //当pct 为100的时候完全透明
    public function imagecopymerge($src, $dx, $dy, $sx, $sy, $sw, $sh, $pct = 1, $blur = false, $rotate = 0, $roatteColor = 0xc5b9b2)
    {
        $src = $this->getHandler($src);
        if ($rotate != 0) {
            $src = imagerotate($src, $rotate, $roatteColor);
        }

        if ($blur) {
            $src = $this->blur($src);
        }
        imagecopymerge($this->imageResource, $src, $dx, $dy, $sx, $sy, $sw * imagesx($src), $sh * imagesy($src), $pct);
    }

    // 图像压缩
    //  type 压缩类型
    // 1 : 拉伸或压缩到对应的尺寸
    // 2: 等比例缩放
    public function thumb($width,$height,$type = 1){
        $w = $this->getWidth();
        $h = $this->getHeight();

        if($type == 1){
            $img = imagecreatetruecolor($width, $height);
            imagecopyresampled($img,$this->imageResource,0,0,0,0,$width,$height,$w,$h);
        }else{
            $img = imagecreatetruecolor($width, $width * $height / $w);
            imagecopyresampled($img,$this->imageResource,0,0,0,0,$width,$width * $height / $w,$w,$h);
        }

        $this->imageResource = $img;
    }


    // 高斯模糊，针对底图的高斯模糊
    public function pblur($blurFactor = 3)
    {
        // blurFactor has to be an integer
        $blurFactor = round($blurFactor);

        $originalWidth = imagesx($this->imageResource);
        $originalHeight = imagesy($this->imageResource);

        $smallestWidth = ceil($originalWidth * pow(0.5, $blurFactor));
        $smallestHeight = ceil($originalHeight * pow(0.5, $blurFactor));

        // for the first run, the previous image is the original input
        $prevImage = $this->imageResource;
        $prevWidth = $originalWidth;
        $prevHeight = $originalHeight;

        // scale way down and gradually scale back up, blurring all the way
        for ($i = 0; $i < $blurFactor; $i += 1) {
            // determine dimensions of next image
            $nextWidth = $smallestWidth * pow(2, $i);
            $nextHeight = $smallestHeight * pow(2, $i);

            // resize previous image to next size
            $nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
            imagecopyresized($nextImage, $prevImage, 0, 0, 0, 0,
                $nextWidth, $nextHeight, $prevWidth, $prevHeight);

            // apply blur filter
            imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);

            // now the new image becomes the previous image for the next step
            $prevImage = $nextImage;
            $prevWidth = $nextWidth;
            $prevHeight = $nextHeight;
        }

        // scale back to original size and blur one more time
        imagecopyresized($this->imageResource, $nextImage,
            0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
        imagefilter($this->imageResource, IMG_FILTER_GAUSSIAN_BLUR);

        // clean up
        imagedestroy($prevImage);
    }

    // 图片高斯模糊，针对底图上的水印图片
    private function blur($gdImageResource, $blurFactor = 3)
    {
        // blurFactor has to be an integer
        $blurFactor = round($blurFactor);

        $originalWidth = imagesx($gdImageResource);
        $originalHeight = imagesy($gdImageResource);

        $smallestWidth = ceil($originalWidth * pow(0.5, $blurFactor));
        $smallestHeight = ceil($originalHeight * pow(0.5, $blurFactor));

        // for the first run, the previous image is the original input
        $prevImage = $gdImageResource;
        $prevWidth = $originalWidth;
        $prevHeight = $originalHeight;

        // scale way down and gradually scale back up, blurring all the way
        for ($i = 0; $i < $blurFactor; $i += 1) {
            // determine dimensions of next image
            $nextWidth = $smallestWidth * pow(2, $i);
            $nextHeight = $smallestHeight * pow(2, $i);

            // resize previous image to next size
            $nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
            imagecopyresized($nextImage, $prevImage, 0, 0, 0, 0,
                $nextWidth, $nextHeight, $prevWidth, $prevHeight);

            // apply blur filter
            imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);

            // now the new image becomes the previous image for the next step
            $prevImage = $nextImage;
            $prevWidth = $nextWidth;
            $prevHeight = $nextHeight;
        }

        // scale back to original size and blur one more time
        imagecopyresized($gdImageResource, $nextImage,
            0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
        imagefilter($gdImageResource, IMG_FILTER_GAUSSIAN_BLUR);

        // clean up
        imagedestroy($prevImage);

        // return result
        return $gdImageResource;
    }


    // 输出并释放资源
    public function outputBower($type = 'jpeg')
    {
        if ($type == 'jpeg' || $type == 'jpg') {
            header('Content-type: image/jpeg');
            imagejpeg($this->imageResource);
        } else {
            header('Content-type: image/png');
            imagesavealpha($this->imageResource, true);
            imagepng($this->imageResource);
        }
        $this->destory();
    }

    // 输出图片到文件中
    public function ouputFile($filename, $type = 'jpeg')
    {
        if ($type == 'jpeg' || $type == 'jpg') {
            imagejpeg($this->imageResource, $filename);
        } else {
            imagesavealpha($this->imageResource, true);
            imagepng($this->imageResource, $filename);
        }
        $this->destory();
    }

    // 销毁所有的头像资源
    private function destory()
    {
        foreach ($this->resourceList as $item) {
            imagedestroy($item);
        }
        imagedestroy($this->imageResource);
    }


    // tool `function`

    public function getWidth()
    {
        return imagesx($this->imageResource);
    }

    public function getHeight()
    {
        return imagesy($this->imageResource);
    }

    // 获取资源头像的句柄
    public function getHandler($file)
    {
        $extension = pathinfo($file)['extension'];

        if (!in_array($extension, $this->allow_ext)) {
            throw new Exception('类型不允许');
        }

        if ($extension == 'jpeg' || $extension == 'jpg') {
            $handler = imagecreatefromjpeg($file);
        } else {
            $handler = imagecreatefrompng($file);
        }
        $this->resourceList[] = $handler;

        return $handler;
    }

    // alpha channel range 0-127 [0:完全不透明，127:完全透明]
    // 转换rgb颜色值
    private function colorallocate($color, $alpha = 0)
    {
        $color = strtolower($color);
        $colorLength = strlen($color);

        switch ($colorLength) {
            case 3:
                # code...
                $red = substr($color, 0, 2);
                $green = substr($color, 2, 2);
                $blue = substr($color, 4, 2);
                break;

            case 6:
                # code...
                $red = substr($color, 0, 1) . "0";
                $green = substr($color, 1, 1) . "0";
                $blue = substr($color, 2, 1) . "0";
                break;

            default:
                throw new Exception("color length error! example:ffffff or fff", 1);
                break;
        }
        return imagecolorallocatealpha($this->imageResource, hexdec($red), hexdec($green), hexdec($blue), $alpha);
    }

}